/*
Copyright (c) 2008 Ryan BB Schreiber, Brendan G Fry

Permission is hereby granted, free of charge, to any person obtaining a copy of 
this software and associated documentation files (the "Software"), to deal in 
the Software without restriction, including without limitation the rights to 
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of the Software, and to permit persons to whom the Software is furnished to do 
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all 
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
*/
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using Darkside.GeneratorStudio.Library;
using Darkside.GeneratorStudio.Library.Domain;
using Darkside.GeneratorStudio.Library.Events;
using Darkside.GeneratorStudio.Library.Generator;
using Darkside.GeneratorStudio.UI.UserControls;
using log4net;

namespace Darkside.GeneratorStudio.UI
{
    public partial class MainForm : Form
    {
        #region LogSetup
        private static readonly ILog _Log = LogManager.GetLogger(typeof(MainForm));
        #endregion


        private bool _MustLoad;
        private bool _saved;
        public bool Saved
        {
            get
            {
                return _saved;
            }
            set
            {
                //If it's the same value, just exit
                if (_saved==value)
                    return;
                _saved = value;
                //Add the asterix or remove it
                if (!_saved)
                    Text += " *";
                else
                    Text = Text.Replace(" *", "");
            }
        }


        private string _fileName;
        public MainForm()
        {

            InitializeComponent();
            projectTreeView.Enabled = false;
            Saved = true;
            _fileName = String.Empty;
            _MustLoad = false;
        }

        public MainForm (string projectFileName):this()
        {
            if (File.Exists(projectFileName))
            {
                _fileName = projectFileName;
                _MustLoad = true;
            }

        }

        Project _Project;
        private void PopulateInformation()
        {
            projectTreeView.Nodes[0].Nodes.Clear();
            mainProgressBar.Visible = true;
            if (_Project == null)
            {
                throw new Exception("Project load error");
            }
            projectTreeView.Enabled = true;
            foreach (Table table in _Project.Tables)
            {

                var tn = new TreeNode(table.Name) {Tag = table};
                if (table.IsView)
                {
                    tn.ImageIndex = 2;
                    tn.SelectedImageIndex = 2;
                }
                tn.Checked = table.Settings.Active;
                projectTreeView.Nodes[0].Nodes.Add(tn);

            }
            projectTreeView.Nodes[0].Text = _Project.SolutionNameSpace;
            projectTreeView.Nodes[0].ImageIndex = 1;
            projectTreeView.Nodes[0].Tag = _Project;
            if (informationPanel.Controls.Count > 0)
            {
                if (informationPanel.Controls[0] is ProjectInfoControl)
                {
                    (informationPanel.Controls[0] as ProjectInfoControl).Populate(_Project);
                }
            }
            projectTreeView.Nodes[0].Checked = _Project.AllSelected;
            mainProgressBar.Visible = false;
            statusToolStripLabel.Text = "Ready.";
            projectTreeView.SelectedNode = projectTreeView.Nodes[0];
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void tvwMain_AfterSelect(object sender, TreeViewEventArgs e)
        {
            try
            {
                SetCursorWait();
                if (e.Node.Tag is Table)
                {
                    if (informationPanel.Controls.Count == 1)
                    {
                        if (informationPanel.Controls[0] is TableInfoControl)
                        {
                            (informationPanel.Controls[0] as TableInfoControl).Populate(e.Node.Tag as Table);
                            return;
                        }
                    }

                    informationPanel.Controls.Clear();
                    var ctl = new TableInfoControl(_Project, (e.Node.Tag as Table));
                    informationPanel.Controls.Add(ctl);
                    ctl.Dock = DockStyle.Fill;
                }
                else if (e.Node.Tag is Project)
                {
                    if (informationPanel.Controls.Count == 1)
                    {
                        if (informationPanel.Controls[0] is ProjectInfoControl)
                        {
                            (informationPanel.Controls[0] as ProjectInfoControl).Populate(_Project);
                            return;
                        }
                    }

                    informationPanel.Controls.Clear();
                    var ctl = new ProjectInfoControl(_Project);
                    informationPanel.Controls.Add(ctl);
                    ctl.Dock = DockStyle.Fill;
                }
            }
            finally
            {
                SetCursorDefault();
            }
        }

        private void tvwMain_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Tag is Project)
            {
                Saved = false;
                //if (e.Node.Checked != (e.Node.Tag as Project).AllSelected) - bf: why were we doing this?
                //{
                    foreach (TreeNode tn in e.Node.Nodes)
                    {
                        tn.Checked = e.Node.Checked;
                    }
                //}
                (e.Node.Tag as Project).AllSelected = e.Node.Checked;
                //update the control
                if (informationPanel.Controls.Count > 0)
                {
                    if (informationPanel.Controls[0] is ProjectInfoControl)
                    {
                        (informationPanel.Controls[0] as ProjectInfoControl).Populate(e.Node.Tag as Project);
                    }
                }
            }

            if (e.Node.Tag is Table)
            {
                Saved = false;
                var t = e.Node.Tag as Table;
                t.Settings.Active = e.Node.Checked;
                //(projectTreeView.Nodes[0].Tag as Project).Tables[t.Name] = t;
                //update the control
                if (informationPanel.Controls.Count > 0)
                {
                    if (informationPanel.Controls[0] is TableInfoControl)
                    {
                        (informationPanel.Controls[0] as TableInfoControl).Populate(e.Node.Tag as Table);
                    }
                }
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Saved)
            {
                if (MessageBox.Show("You have not saved the changes you have made. Are you sure you wish to continue?", "Darkside Generator Studio", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    return;
                }
            }
            if (projectOpenFileDialog.ShowDialog() == DialogResult.OK)
            {
                LoadProject(projectOpenFileDialog.FileName);
            }
        }

        private void LoadProject(string fileName)
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                Application.DoEvents();
                _Project = Project.LoadProject(fileName);
                PopulateInformation();
                Text = "Darkside Generator Studio - " + fileName;
                Saved = true;
                _fileName = fileName;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }

        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!Saved)
            {
                if (MessageBox.Show("You have not saved the changes you have made. Are you sure you wish to continue?", "Darkside Generator Studio", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    return;
                }
            }
            _Project = null;

            var sqlDialog = new SQLConnectionDialog();
            if (sqlDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    SetStatus("Retrieving database information...");
                    Cursor = Cursors.WaitCursor;
                    this.Refresh();
                    Application.DoEvents();
                    ActiveRecordInitialiser.Initialise(sqlDialog.ConnectionString); 
                    _Project = new Project
                                   {
                                       SolutionNameSpace = "Namespace",
                                       OutputPath = "c:\\temp",
                                       ConnectionString = sqlDialog.ConnectionString
                                   };
                    _Project.Initialise();
                    PopulateInformation();
                }
                finally
                {
                    Cursor = Cursors.Default;
                    SetStatus("Ready.");
                }
                _fileName = String.Empty;
                Saved = false;
                Text = "Darkside Generator Studio - New Tempate *";
            }
        }

        private void UpdateProject(bool checkItems)
        {
            if (informationPanel.Controls.Count > 0)
            {
                if (informationPanel.Controls[0] is ProjectInfoControl)
                {
                    if (projectTreeView.SelectedNode != null)
                    {
                        if (projectTreeView.SelectedNode.Tag is Project)
                        {
                            projectTreeView.SelectedNode.Tag = (informationPanel.Controls[0] as ProjectInfoControl).UpdateItemObject();
                            if (checkItems)
                                projectTreeView.SelectedNode.Checked = (projectTreeView.SelectedNode.Tag as Project).AllSelected;
                            projectTreeView.SelectedNode.Text = (projectTreeView.SelectedNode.Tag as Project).SolutionNameSpace;
                        }
                    }
                }
                else if (informationPanel.Controls[0] is TableInfoControl)
                {
                    if (projectTreeView.SelectedNode != null)
                    {
                        if (projectTreeView.SelectedNode.Tag is Table)
                        {
                            projectTreeView.SelectedNode.Tag = (informationPanel.Controls[0] as TableInfoControl).UpdateItemObject();
                            if (checkItems)
                                projectTreeView.SelectedNode.Checked = (projectTreeView.SelectedNode.Tag as Table).Settings.Active;
                        }
                    }
                }
            }
        }

        private void Generate(bool generateAll)
        {
            if (_Project != null && _Project.Tables.Count > 0)
            {
                if (string.IsNullOrEmpty(_Project.OutputPath))
                {
                    MessageBox.Show(this, "Please enter an output path for the generated code.", "Darkside Generator Studio", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }


                if (!Directory.Exists(_Project.OutputPath))
                {
                    MessageBox.Show(this, "Please ensure that the output directory exists.", "Darkside Generator Studio", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                generateToolStripMenuItem.Enabled = false;
                openToolStripMenuItem.Enabled = false;

                UpdateProject(true);
                generateBackgrounWorkerThread.RunWorkerAsync(generateAll);
            }
        }

        private void tvwMain_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            UpdateProject(true);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!Saved)
            {
                if (MessageBox.Show(this, "You have unsaved changes. Are you sure you want to exit Generator Studio?", "Darkside Generator Studio", MessageBoxButtons.YesNo, MessageBoxIcon.Question) !=
                    DialogResult.Yes)
                {
                    e.Cancel = true;
                }
            }
        }

        private void generateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Generate(false);
        }

        private void generateBackgroundWorkerThread_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                var modelGen = new ModelGenerator(_Project);
                modelGen.GenerateClasses();
            }
            catch (Exception ex)
            {
                _Log.Error(ex.Message, ex);
            }
        }


        private void generateBackgroundWorkerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Application.DoEvents();
            MessageBox.Show(this, "Completed generating.", "Darkside Generator Studio", MessageBoxButtons.OK, MessageBoxIcon.Information);
            generateToolStripMenuItem.Enabled = true;
            openToolStripMenuItem.Enabled = true;
            mainProgressBar.Visible = false;
            statusToolStripLabel.Text = "Ready.";
        }

        private void refreshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (_Project != null && _Project.Tables.Count > 0)
                {
                    _Project.Refresh();
                    PopulateInformation();
                }
            }
            catch (System.Data.SqlClient.SqlException sqlEx)
            {
                MessageBox.Show(this, sqlEx.Message, "Darkside Generator Studio", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetCursorWait();
            if (!SaveProject(false))
                MessageBox.Show("Project could not be saved", "Darkside Generator Studio", MessageBoxButtons.OK, MessageBoxIcon.Error);
            SetCursorDefault();
        }

        private void SetCursorWait()
        {
            Cursor = Cursors.WaitCursor;
            Application.DoEvents();
        }

        private void SetCursorDefault()
        {
            Cursor = Cursors.Default;
            Application.DoEvents();
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetCursorWait();
            if (!SaveProject(true))
                MessageBox.Show("Project could not be saved", "Darkside Generator Studio", MessageBoxButtons.OK, MessageBoxIcon.Error);
            
            SetCursorDefault();
        }

        private bool SaveProject(bool saveAs)
        {
            try
            {
                if (String.IsNullOrEmpty(_fileName) || saveAs)
                {
                    if (projectSaveFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        _fileName = projectSaveFileDialog.FileName;
                    }
                    else
                        return (true);
                }
                
                //_Project.ProgressEvent -= new EventHandler<ProgressEventArgs>(Project_ProgressEvent);
                if (projectTreeView.Nodes[0].Nodes.Count > 0)
                {
                    if (projectTreeView.Nodes[0].Tag is Project)
                    {
                        if (informationPanel.Controls.Count > 0)
                        {
                            if (informationPanel.Controls[0] is ProjectInfoControl)
                            {
                                projectTreeView.SelectedNode.Tag = (informationPanel.Controls[0] as ProjectInfoControl).UpdateItemObject();
                            }
                        }
                        Project.SaveProject((projectTreeView.Nodes[0].Tag as Project), _fileName);
                    }
                }
                Text = "Darkside Generator Studio - " + _fileName;
                PopulateInformation();
                _fileName = projectSaveFileDialog.FileName;
                Saved = true;
            }
            catch (Exception ex)
            {
                _Log.Error("SaveProject", ex);
                return (false);
            }
            return (true);
        }


        private void SetStatus(string status)
        {
            statusToolStripLabel.Text = status;
            Application.DoEvents();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            
            GlobalEvents.StatusEvent += GlobalEvents_StatusEvent;
        }

        void GlobalEvents_StatusEvent(object sender, StatusEventArgs e)
        {
            SetStatusDelegate d = SetStatus;
            Invoke(d, e);
        }

        delegate object SetStatusDelegate(StatusEventArgs e);

        object SetStatus(StatusEventArgs e)
        {
            mainProgressBar.Maximum = e.TotalTasks;
            if (e.TotalTasks > 0)
            {
                mainProgressBar.Visible = true;
                mainProgressBar.Value = e.CurrentTask;
            }
            statusToolStripLabel.Text = e.Message;
            Application.DoEvents();
            return null;
        }

        private void projectTreeView_BeforeCheck(object sender, TreeViewCancelEventArgs e)
        {
            UpdateProject(false);
        }

        private void mnuHelpLicense_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.codeplex.com/generatorstudio/license");
        }

        private void mnuHelpDocumentation_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.codeplex.com/generatorstudio/Thread/View.aspx?ThreadId=39270");
        }

        private void mnuHelpAbout_Click(object sender, EventArgs e)
        {
            var frm = new AboutForm();
            frm.ShowDialog();
        }

        private void MainForm_Activated(object sender, EventArgs e)
        {
            if (_MustLoad)
            {
                _MustLoad = false;
                Application.DoEvents();
                LoadProject(_fileName);
            }
        }
    }
}


